//#include "stdafx.h"
#include <mzfc_inc.h>
#include "STScreenBuffer.h"

/*#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif*/

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

int CSTScreenBuffer::CorrectedWidth(int nWidth)
{
	return ( ( nWidth + 3 ) / 4 ) * 4;
}

struct DIBINFO : public BITMAPINFO
{
	RGBQUAD	 arColors[255];    // Color table info - adds an extra 255 entries to palette

	operator LPBITMAPINFO()          { return (LPBITMAPINFO) this; }
	operator LPBITMAPINFOHEADER()    { return &bmiHeader;          }
	RGBQUAD* ColorTable()            { return bmiColors;           }
};


/////////////////////////////////////////////////////////////////////////////
// CSTScreenBuffer

CSTScreenBuffer::CSTScreenBuffer()
	: m_hBitmap(NULL),
	  m_pBuffer(NULL),
	  m_pDC(NULL)
{
}

CSTScreenBuffer::~CSTScreenBuffer()
{
	if (m_hBitmap!=NULL) {
		ReleaseDC();
		::DeleteObject(m_hBitmap);
	}
}

BOOL CSTScreenBuffer::CreateBitmap(int nWidth, int nHeight)
{
	ASSERT(nWidth>0);
	ASSERT(nHeight>0);

	if (m_hBitmap!=NULL) DeleteObject(m_hBitmap);

	m_nCorrectedWidth = CorrectedWidth(nWidth);
	m_nWidth = nWidth;
	m_nHeight = nHeight;

	DIBINFO  dibInfo;

	dibInfo.bmiHeader.biBitCount = 24;
	dibInfo.bmiHeader.biClrImportant = 0;
	dibInfo.bmiHeader.biClrUsed = 0;
	dibInfo.bmiHeader.biCompression = 0;
	dibInfo.bmiHeader.biHeight = m_nHeight;
	dibInfo.bmiHeader.biPlanes = 1;
	dibInfo.bmiHeader.biSize = 40;
	dibInfo.bmiHeader.biSizeImage = m_nCorrectedWidth*m_nHeight*3;
	dibInfo.bmiHeader.biWidth = m_nCorrectedWidth;
	dibInfo.bmiHeader.biXPelsPerMeter = 3780;
	dibInfo.bmiHeader.biYPelsPerMeter = 3780;
	dibInfo.bmiColors[0].rgbBlue = 0;
	dibInfo.bmiColors[0].rgbGreen = 0;
	dibInfo.bmiColors[0].rgbRed = 0;
	dibInfo.bmiColors[0].rgbReserved = 0;

	HDC hDC = ::GetDC(NULL);
	ASSERT(hDC);
	m_hBitmap = CreateDIBSection(hDC, (const BITMAPINFO*)dibInfo, DIB_RGB_COLORS, (void**)&m_pBuffer, NULL, 0);
	::ReleaseDC(NULL, hDC);
	ASSERT(m_hBitmap);
	ASSERT(m_pBuffer);

	return TRUE;
}

void CSTScreenBuffer::Create(int nWidth, int nHeight)
{
	ASSERT(nWidth>0);
	ASSERT(nHeight>0);

	CreateBitmap(nWidth, nHeight);
}

void CSTScreenBuffer::Create(int nWidth, int nHeight, COLORREF clr)
{
	ASSERT(nWidth>0);
	ASSERT(nHeight>0);

	CreateBitmap(nWidth, nHeight);

	BGRColor bgrColor = BGRColor(GetBValue(clr), GetGValue(clr), GetRValue(clr));
	int nPosition = 0;

	for (int y=0; y<nHeight; y++) {
		nPosition = m_nCorrectedWidth*y;
		for (int x=0; x<nWidth; x++) {
			m_pBuffer[nPosition] = bgrColor;
			nPosition++;
		}
	}
}

void CSTScreenBuffer::Create(HBITMAP hBitmap)
{
	BITMAP bm;
	GetObject(hBitmap, sizeof(BITMAP), &bm);
	CreateBitmap(bm.bmWidth, bm.bmHeight);

#ifdef _I8_MID_SDK_
	CDC memDc;
	CDC targetDc;	

#else
	CMzDC memDc;
	CMzDC targetDc;
#endif
	memDc.CreateCompatibleDC(NULL);
	targetDc.CreateCompatibleDC(NULL);

	HBITMAP hOldBitmap1 = (HBITMAP)::SelectObject(memDc.m_hDC, hBitmap);
	HBITMAP hOldBitmap2 = (HBITMAP)::SelectObject(targetDc.m_hDC, m_hBitmap);

	targetDc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, memDc, 0, 0, SRCCOPY);

	::SelectObject(memDc.m_hDC, hOldBitmap1);
	::SelectObject(targetDc.m_hDC, hOldBitmap2);
	memDc.DeleteDC();
	targetDc.DeleteDC();
}
#ifdef _I8_MID_SDK_
void CSTScreenBuffer::Create(CDC *pDC, CRect rect)
#else
void CSTScreenBuffer::Create(CMzDC *pDC, CMzRect rect)
#endif
{
	ASSERT(pDC);

	CreateBitmap(rect.Width(), rect.Height());
	GetDC()->BitBlt(0,0, rect.Width(), rect.Height(), pDC->m_hDC, rect.left, rect.top, SRCCOPY);
}

void CSTScreenBuffer::CreateRGB(void *pData, int nWidth, int nHeight)
{
	ASSERT(pData);
	ASSERT(nWidth>0);
	ASSERT(nHeight>0);

	CreateBitmap(nWidth, nHeight);

	byte *pByteData = (byte*)pData;
	int nPosition = 0;
	int nDataPosition = 0;

	for (int y=0; y<nHeight; y++) {
		nPosition = m_nCorrectedWidth*(m_nHeight-y-1);
		nDataPosition = nWidth*3*y;
		for (int x=0; x<nWidth; x++) {
			m_pBuffer[nPosition].m_R = pByteData[nDataPosition++];
			m_pBuffer[nPosition].m_G = pByteData[nDataPosition++];
			m_pBuffer[nPosition].m_B = pByteData[nDataPosition++];
			nPosition++;
		}
	}
}
#ifdef _I8_MID_SDK_
BOOL CSTScreenBuffer::Draw(CDC* pDC, CPoint ptDest)
#else
BOOL CSTScreenBuffer::Draw(CMzDC* pDC, CMzPoint ptDest)
#endif
{
	ASSERT(m_hBitmap);
	ReleaseDC();

#ifdef _I8_MID_SDK_
	CPoint ptOrigin = CPoint(0,0);
#else
	CMzPoint ptOrigin = CMzPoint(0,0);
#endif

	BOOL bResult = FALSE;

#ifdef _I8_MID_SDK_
	CDC memDc;
#else
	CMzDC memDc;
#endif
	if (!memDc.CreateCompatibleDC(pDC->m_hDC)) {
		return FALSE;
	}

	HBITMAP m_hOldBitmap = (HBITMAP)::SelectObject(memDc.m_hDC, m_hBitmap);
	bResult = pDC->BitBlt(ptDest.x, ptDest.y, m_nWidth, m_nHeight, memDc.m_hDC, ptOrigin.x, ptOrigin.y, SRCCOPY);
	::SelectObject(memDc.m_hDC, m_hOldBitmap);
	memDc.DeleteDC();

	return bResult;
}


HBITMAP CSTScreenBuffer::CreateBitmapByRGBArray(void *pData, int nWidth, int nHeight)
{
	HBITMAP hResult = NULL;	
	CSTScreenBuffer sb;

	sb.CreateRGB(pData, nWidth, nHeight);
	hResult = sb.m_hBitmap;

	sb.m_hBitmap = NULL;
	sb.m_pBuffer = NULL;

	return hResult;
}

#ifdef _I8_MID_SDK_
CDC *CSTScreenBuffer::GetDC()
#else
CMzDC *CSTScreenBuffer::GetDC()
#endif
{
	if (m_pDC) return m_pDC;

#ifdef _I8_MID_SDK_
	m_pDC = new CDC();
#else
	m_pDC = new CMzDC();
#endif
	if (!m_pDC->CreateCompatibleDC(NULL)) {
		delete m_pDC;
		return NULL;
	}

	m_hSaveBitmap = (HBITMAP)SelectObject(m_pDC->m_hDC, GetHBitmap());
	return m_pDC;
}

void CSTScreenBuffer::ReleaseDC()
{
	if (m_pDC) {
		SelectObject(m_pDC->m_hDC, m_hSaveBitmap);
		m_pDC->DeleteDC();
		delete m_pDC;
		m_pDC = NULL;
	}
}
